package com.smartinput.sse.application.service

import com.fasterxml.jackson.databind.ObjectMapper
import com.smartinput.sse.application.dto.*
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter
import java.util.concurrent.ConcurrentHashMap

@Service
class SSEService {
    private val logger = LoggerFactory.getLogger(javaClass)
    private val userConnections = ConcurrentHashMap<String, MutableSet<SSEConnection>>()
    private val objectMapper = ObjectMapper()

    fun registerConnection(userId: String, deviceId: String, emitter: SseEmitter) {
        val connection = SSEConnection(deviceId, emitter)
        userConnections.computeIfAbsent(userId) { mutableSetOf() }.add(connection)

        // 设置连接关闭处理
        emitter.onCompletion {
            userConnections[userId]?.remove(connection)
            logger.info("SSE连接完成: userId=$userId, deviceId=$deviceId")
        }

        emitter.onTimeout {
            userConnections[userId]?.remove(connection)
            logger.info("SSE连接超时: userId=$userId, deviceId=$deviceId")
        }

        emitter.onError { throwable ->
            logger.error("SSE连接错误: userId=$userId, deviceId=$deviceId", throwable)
            userConnections[userId]?.remove(connection)
        }

        logger.info("SSE连接注册: userId=$userId, deviceId=$deviceId")
    }

    fun sendEvent(userId: String, message: SSEMessage) {
        val connections = userConnections[userId] ?: return

        connections.forEach { connection ->
            try {
                val eventData = objectMapper.writeValueAsString(message)
                connection.emitter.send(
                    SseEmitter.event()
                        .name(message.type)
                        .data(eventData)
                        .id(System.currentTimeMillis().toString())
                )
            } catch (e: Exception) {
                logger.error("发送SSE事件失败: deviceId=${connection.deviceId}", e)
                connections.remove(connection)
            }
        }
    }

    fun sendNotification(userId: String, notification: NotificationRequest) {
        val message = SSEMessage(
            type = "notification",
            data = mapOf(
                "title" to notification.title,
                "message" to notification.message,
                "type" to notification.type,
                "timestamp" to System.currentTimeMillis()
            )
        )
        sendEvent(userId, message)
    }

    fun notifyDeviceStatusChange(userId: String, deviceId: String, online: Boolean) {
        val message = SSEMessage(
            type = "device_status_change",
            data = mapOf(
                "deviceId" to deviceId,
                "online" to online,
                "timestamp" to System.currentTimeMillis()
            )
        )
        sendEvent(userId, message)
    }

    fun broadcastSystemMessage(message: String) {
        userConnections.keys.forEach { userId ->
            val sseMessage = SSEMessage(
                type = "system_message",
                data = mapOf(
                    "message" to message,
                    "timestamp" to System.currentTimeMillis()
                )
            )
            sendEvent(userId, sseMessage)
        }
    }

    fun sendToDevice(deviceId: String, eventType: String, data: Any): Boolean {
        var success = false

        userConnections.values.forEach { connections ->
            connections.find { it.deviceId == deviceId }?.let { connection ->
                try {
                    val message = SSEMessage(
                        type = eventType,
                        data = mapOf(
                            "data" to data,
                            "timestamp" to System.currentTimeMillis()
                        )
                    )

                    val eventData = objectMapper.writeValueAsString(message)
                    connection.emitter.send(
                        SseEmitter.event()
                            .name(eventType)
                            .data(eventData)
                            .id(System.currentTimeMillis().toString())
                    )
                    success = true
                    logger.info("SSE消息发送成功: deviceId=$deviceId, eventType=$eventType")
                } catch (e: Exception) {
                    logger.error("SSE消息发送失败: deviceId=$deviceId, eventType=$eventType", e)
                    connections.remove(connection)
                }
            }
        }

        return success
    }

    fun getConnectedDevices(userId: String): List<String> {
        return userConnections[userId]?.map { it.deviceId } ?: emptyList()
    }

    fun isDeviceConnected(deviceId: String): Boolean {
        return userConnections.values.any { connections ->
            connections.any { it.deviceId == deviceId }
        }
    }

    fun removeConnection(userId: String, deviceId: String) {
        userConnections[userId]?.removeIf { it.deviceId == deviceId }
        logger.info("SSE连接移除: userId=$userId, deviceId=$deviceId")
    }
} 